function TITTProxyGenerator() {
	
	this.generateProxy = function(invoker, k) {
		invoker.dynCall("showMeYourTITTies", [], function(iface) {
			k(generateFromInterface(invoker, iface));	
		});
	}

	function generateSkeleton(len, funcName, retType, types, f) {
		var args = "";
		for(var i = 0; i < len; i++)
			args += "p"+i+",";
			
		var aargs = args.substring(0, Math.max(args.length-1,0));

		eval("function ret("+args+"k) {f(funcName,retType,types,[" + aargs + "],ret.arguments.length-1,ret.arguments[ret.arguments.length-1]);}");

		return ret;
	}
	
	function invoke(args, func) {
		var argstr = "";
		
		for(var i = 0; i < args.length; i++)
			if(argstr == "")
				argstr += "args["+i+"]";
			else
				argstr += ",args["+i+"]";
			
		return eval("func(" + argstr + ");");
	}
	
	function findOverload(cand, oldcand) {
		function f() {
			if(f.arguments.length == cand.length)
				return invoke(f.arguments, cand);
			return invoke(f.arguments, oldcand);
		}
		return f;
	}
	
	function createHandler(k) {
		return function(retval){
			k(retval.getObject());
		}
	}

	function generateFromInterface(invoker, iface) {
		var ret = new Object();
		var inc = 0;
		
		
		for(var i = 1; i < iface.length; i++) {
						
			var types = [], funcName = iface[i][1];
			
			for(var h = 2; h < iface[i].length; h++)
				types[types.length] = new Type(iface[i][h]);			
			
			var skel = generateSkeleton(types.length, funcName, new Type(iface[i][0]), types, createInvokeHandler(invoker));

			if(ret[funcName])
				ret[funcName] = findOverload(skel, ret[funcName]);
			else
				ret[funcName] = skel;			
		}
		
		return ret;
	}
	
	function createInvokeHandler(invoker) {
		return function(funcName, retType, types, args, arglen, k) {

				var typedArgs = [];
				
				for(var j = arglen; j < args.length; j++)
					args[j] = null;

				for(var j = 0; j < types.length; j++) {
					if(types[j].equals(Types.UNKNOWN))
						typedArgs[typedArgs.length] = new TypedObject(new TypeFromObject(args[j]),args[j]);
					else
						typedArgs[typedArgs.length] = new TypedObject(types[j], args[j]);
				}
				invoker.advCall(funcName, retType, typedArgs, createHandler(k));

			}
	}
	
}


/*
function TITTProxyGenerator() {
		
	this.generateProxy = function(tokens, k) {
		var inv = new TITTInvoker(tokens);
		
		inv.dynCall("showMeYourTITTies", [], function(iface) {
			k(generateFromInterface(inv, iface));
		});
	}
	
	function generateFromInterface(d, iface) {
			var retObj = new Object();
		
			for(var i = 1; i < iface.length; i++) {

				var ret = new Type(iface[i][0]);
				var nam = iface[i][1];
				var args = new Array();
				var argstr = "", targstr = "";
				
				for(var h = 2; h < iface[i].length; h++)
					args[h-2] = new Type(iface[i][h]);
				
				for(var h = 0; h < args.length; h++) {
					if(h > 0) targstr += ",";
					argstr += "arg" + h + ",";
					
					var t = "new Type(\"" + args[h].asString() + "\")";
					if(args[h].equals(Types.UNKNOWN))
						t = "new TypeFromObject(arg" + h + ")";
					
					targstr += "new TypedObject(" + t + ", arg" + h + ")";
				}
				var fbod = "d.call(\"" + nam + "\", [" + targstr + "], function(ret) { k(ret.getObject()); } );";
				
				argstr += "k";

				//sync toString fix
				if(nam == "toString") {
					fbod = "if(k) { " + fbod + " } else { return \"[object Proxy]\"; }";
				}

				var fstr = "retObj." + nam + " = function(" + argstr + ") { " + fbod + " }";

				eval(fstr);

			}

			return retObj;		
	}
}
*/